Как уменьшить размер Java-контейнеров в Docker

Как уменьшить размер Docker-образа для Java-приложений


Декабрь 15, 2023


Контейнеры значительно облегчили разработку, тестирование, и деплой облачно-нативных приложений, а существующие технологии автоматической сборки контейнеров еще сильнее ускорили эти процессы. Но если не следить за размером контейнера, ИТ-команда может столкнуться с ростом потребления облачных ресурсов и другими проблемами.

В этой статье мы расскажем об эффективных методах уменьшения Docker-образов, на основе которых можно строить легковесные контейнеры для Java-приложений.

Оптимизация базового образа ОС

Выбор Linux-дистрибутива для Docker-образа

Первый и самый действенный шаг к уменьшению размера Docker-образа — выбор базового образа ОС. Размер Linux-дистрибутива, используемого для контейнеризации приложений, может варьироваться от 79 МБ (CentOS) до 3 МБ (Alpine Linux), что существенно влияет на размер итогового образа. Однако помимо размера при выборе Linux-дистрибутива следует ориентироваться и на другие важные факторы, такие как:

  • Регулярные обновления. Поскольку контейнеры являются неотъемлемой частью корпоративной ИТ-инфраструктуры, требования информационной безопасности распространяются и на них. Контейнеры необходимо обновлять (как слой JDK, так и Linux), чтобы оперативно устранять известные уязвимости. Поэтому выбор нужно сделать в пользу Linux-дистрибутива, чьи разработчики своевременно внедряют патчи безопасности в свой продукт.
  • Реализация библиотеки C (libc). Большинство современных Linux-дистрибутивов основаны на реализации стандартной библиотеки C под названием glibc, некоторые (такие как Alpine) – на musl. Использование дистрибутива на musl помогает значительно сократить размер контейнера, но переход на ОС с другой имплементацией libc в основе может вызвать проблемы с совместимостью и непредсказуемое поведение приложения.
  • Наличие техподдержки на территории России. У некоторых Linux-дистрибутивов есть только поддержка от сообщества, что не оптимально для корпоративной разработки, поскольку решения проблемы можно ждать несколько недель. С другой стороны, зарубежные вендоры из-за угрозы санкций больше не оказывают поддержку своих продуктов в России, поэтому использовать их в корпоративной разработке также не рекомендуется. Альтернативу зарубежным решениям можно найти в Едином реестре российского ПО.

Команда Axiom JDK разрабатывает и поддерживает Axiom Runtime Container Pro, который входит в реестр российского ПО. Решение основано на легковесном Axiom Linux с поддержкой двух вариантов libc (улучшенный musl и glibc) и рантайме Axiom JDK Pro Lite, оптимизированном для деплоя в облаке.

Сокращение количества Linux-пакетов

Какой бы Linux-дистрибутив вы ни выбрали, его можно кастомизировать. В большинстве случаев базовые Linux-образы содержат множество дополнительных модулей. Удалите пакеты, которые не нужны для работы вашего приложения — так вы еще сильнее уменьшите размер образа.

Можно пойти другим путем: используйте минималистичный Linux-дистрибутив и вместо того, чтобы удалять ненужные библиотеки, добавьте только необходимые, скачав их из Linux-репозиториев.

Оптимизация Java-слоев

Thin JAR-файлы

Традиционным способом упаковки Java-приложений является создание так называемых fat JAR-файлов, содержащих файлы классов и приложение со всеми зависимостями. В итоге мы получаем исполняемый файл, которому для запуска необходима лишь среда исполнения (JRE).

Но мы можем уменьшить размер исполняемого файла, создав thin JAR с приложением без зависимостей. Разработчики кладут зависимости в отдельные слои в образе, а сверху кладут thin JAR. Это позволяет, во-первых, хранить зависимости в локальном репозитории и не перемещать приложение со всеми зависимостями из среды разработки в среду тестирования или в прод, а во-вторых, иметь один общий редко обновляемый набор слоев зависимостей и обновлять только самый тонкий слой, что сильно экономит время.

JRE для деплоя

Для разработки Java-приложений требуется среда разработки и исполнения Java Development Kit (JDK), включающая в себя виртуальную машину Java (JVM), среду исполнения (JRE) и инструменты разработчика (дебаггер, компилятор и т.д.). Однако для запуска приложения нужна только JRE, включающая JVM и некоторые классы для выполнения кода.

Иногда разработчики помещают JDK в контейнеры, предназначенные для прода, тем самым необоснованно увеличивая их размер. Для прода больше подходят JRE-образы. Сравните: образ JDK с дополнительными инструментами, такими как jlink, занимает около 160 МБ, в то время как JRE (на базе Axiom JDK Pro Lite) весит около 40 МБ!

Начиная с версии Java 9, JDK разделена на модули (наборы взаимосвязанных пакетов с дескриптором модуля). Сами Java-приложения также можно организовать в виде модулей. Благодаря этой особенности Java-платформы разработчики с помощью инструмента jlink могут создавать кастомные JRE-образы, содержащие только модули, необходимые их приложению. Итоговый контейнер на базе кастомной JRE может занимать в три раза меньше памяти, чем стандартный контейнер.

Полезные Docker-инструменты

Лучшая практика по работе с Dockerfile — минимизация количества слоев. Каждая команда в Dockerfile создает новый слой образа, тем самым увеличивая его размер. Поэтому при возможности команды следует объединять, например, вместо двух RUN do something и RUN do something else написать RUN do something && do something else.

Также для работы с Docker есть инструменты, помогающие уменьшить размер образа:

  • .dockerignore позволяет разработчикам указать файлы и папки, которые не должны попасть в итоговый образ. Таким образом можно ускорить процесс сборки, уменьшить потребление памяти и повысить безопасность, устранив риск попадания в образ конфиденциальных данных.
  • docker-slim автоматически оптимизирует размер образа. Инструмент создает временный образ и анализирует, какие файлы необходимы приложению. Итоговый однослойный образ, содержащий только нужные файлы, может быть в 30 раз меньше изначального. Но использовать docker-slim нужно с осторожностью, поскольку он может ошибиться в расчетах и не учесть необходимые файлы из-за динамизма Java.
  • docker-squash «сплющивает» N последних слоев в один, благодаря чему временные или удаленные файлы не попадут в итоговый образ.

Заключение

Как видите, методов уменьшения Docker-образов много: даже если вы используете лишь некоторые из них, экономия памяти будет существенной.

Для достижения мгновенного результата без существенных изменений конфигурации можно мигрировать на микроконтейнеры Axiom Runtime Container Pro — так вы одновременно уменьшите потребление облачных ресурсов и внедрите в проект отечественную технологию с техподдержкой, что особенно актуально для объектов КИИ, ГИС и финтеха, которые в соответствии с требованиями законодательства должны быть переведены на российское ПО к 2025 году.

Свяжитесь с нами — наши инженеры подробно расскажут об Axiom Runtime Container Pro и других продуктах линейки Axiom JDK, предоставят демо-версии и помогут с миграцией.

Author image

Олег Чирухин

Директор по коммуникациям с разработчиками (DevRel)

Команда Axiom JDK roman.karpov@axiomjdk.ru Команда Axiom JDK logo Axiom Committed to Freedom 199 Obvodnogo Kanala Emb. 190020 St. Petersburg RU +7 812-336-35-67 Команда Axiom JDK 199 Obvodnogo Kanala Emb. 190020 St. Petersburg RU +7 812-336-35-67